﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Zo.Extensions
{
    /// <summary>
    /// 字符串加密扩展。
    /// </summary>
    public static class EncryptExtensions
    {
        #region MD5

        /// <summary>
        /// 将当前字符串转换成 32 位 MD5 加密。
        /// </summary>
        /// <param name="target">当前字符串。</param>
        /// <returns>32 位 MD5 加密后的字符串。</returns>
        public static string MD5(this string target) => target.MD5("", "UTF-8");

        /// <summary>
        /// 将当前字符串转换成 32 位 MD5 加密。
        /// </summary>
        /// <param name="target">当前字符串。</param>
        /// <param name="key">密钥。</param>
        /// <param name="charset">编码格式。</param>
        /// <returns>32 位 MD5 加密后的字符串。</returns>
        public static string MD5(this string target, string key, string charset)
        {
            var md5Text = new StringBuilder(32);

            target += key;

            System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            var data = md5.ComputeHash(Encoding.GetEncoding(charset).GetBytes(target));
            foreach (var text in data)
            {
                md5Text.Append(text.ToString("x").PadLeft(2, '0'));
            }

            return md5Text.ToString();
        }

        #endregion MD5

        #region 3DES 加密与解密

        /// <summary>
        /// 获取加密后的字符串。
        /// </summary>
        /// <param name="inputValue">输入值。</param>
        /// <returns>加密后的字符串。</returns>
        public static string EncryptDes(this string inputValue)
        {
            DESCryptoServiceProvider provider = GetCryptoProvider();
            byte[] bytes = Encoding.GetEncoding("UTF-8").GetBytes(inputValue);
            MemoryStream stream = new MemoryStream();
            CryptoStream stream2 = new CryptoStream(stream, provider.CreateEncryptor(), CryptoStreamMode.Write);
            stream2.Write(bytes, 0, bytes.Length);
            stream2.FlushFinalBlock();
            StringBuilder builder = new StringBuilder();
            foreach (byte num in stream.ToArray())
            {
                builder.AppendFormat("{0:X2}", num);
            }
            stream.Close();
            return builder.ToString();
        }

        /// <summary>
        /// 获取加密服务类。
        /// </summary>
        /// <returns></returns>
        private static DESCryptoServiceProvider GetCryptoProvider()
        {
            string IV = "ScFaoEjpTQun";
            string KEY = "KjPoTuIrGY6fl3gTJvsIsA4NaxiaYBBT";

            DESCryptoServiceProvider provider = new DESCryptoServiceProvider
            {
                IV = Encoding.ASCII.GetBytes(IV.Substring(0, 8)),
                Key = Encoding.ASCII.GetBytes(KEY.Substring(0, 8))
            };

            return provider;
        }

        /// <summary>
        /// 获取解密后的值。
        /// </summary>
        /// <param name="inputValue">经过加密后的字符串。</param>
        /// <returns>解密后的字符串。</returns>
        public static string DecryptDes(this string inputValue)
        {
            DESCryptoServiceProvider provider = GetCryptoProvider();
            byte[] buffer = new byte[inputValue.Length / 2];
            for (int i = 0; i < (inputValue.Length / 2); i++)
            {
                int num2 = Convert.ToInt32(inputValue.Substring(i * 2, 2), 0x10);
                buffer[i] = (byte)num2;
            }
            MemoryStream stream = new MemoryStream();
            CryptoStream stream2 = new CryptoStream(stream, provider.CreateDecryptor(), CryptoStreamMode.Write);
            stream2.Write(buffer, 0, buffer.Length);
            stream2.FlushFinalBlock();
            stream.Close();
            return Encoding.GetEncoding("UTF-8").GetString(stream.ToArray());
        }

        #endregion 3DES 加密与解密

        #region 16 位 AES 加解密

        /// <summary>
        /// AES 加密。
        /// </summary>
        /// <param name="text"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static string AES16Encrypt(this string text, string password = "9D4#!uCb4%&83FO4")
        {
            var rijndaelCipher = new RijndaelManaged
            {
                Mode = CipherMode.ECB,
                Padding = PaddingMode.PKCS7,
                KeySize = 128,
                BlockSize = 128
            };

            byte[] pwdBytes = System.Text.Encoding.UTF8.GetBytes(password);

            byte[] keyBytes = new byte[16];

            int len = pwdBytes.Length;

            if (len > keyBytes.Length) len = keyBytes.Length;

            System.Array.Copy(pwdBytes, keyBytes, len);

            rijndaelCipher.Key = keyBytes;

            ICryptoTransform transform = rijndaelCipher.CreateEncryptor();

            byte[] plainText = Encoding.UTF8.GetBytes(text);
            //var plainText = Encoding.GetEncoding("GB2312").GetBytes(text);

            byte[] cipherBytes = transform.TransformFinalBlock(plainText, 0, plainText.Length);
            string result = string.Empty;
            for (int i = 0; i < cipherBytes.Length; i++)//逐字节变为16进制字符
            {
                result += cipherBytes[i].ToString("X2");// Convert.ToString(cipherBytes[i], 16);
            }
            Console.WriteLine(result);
            return result;
            //return Convert.ToBase64String(cipherBytes);
        }

        /// <summary>
        /// AES 解密。
        /// </summary>
        /// <param name="text"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static string AES16Decrypt(this string text, string password = "9D4#!uCb4%&83FO4")
        {
            RijndaelManaged rijndaelCipher = new RijndaelManaged
            {
                Mode = CipherMode.ECB,
                Padding = PaddingMode.PKCS7,
                KeySize = 128,
                BlockSize = 128
            };

            //byte[] encryptedData = Encoding.UTF8.GetBytes(text);
            byte[] encryptedData = new byte[text.Length / 2];
            for (int i = 0; i < encryptedData.Length; i++)
            {
                try
                {
                    // 每两个字符是一个 byte。
                    encryptedData[i] = byte.Parse(text.Substring(i * 2, 2),
                    System.Globalization.NumberStyles.HexNumber);
                }
                catch
                {
                    // Rethrow an exception with custom message.
                    throw new ArgumentException("hex is not a valid hex number!", nameof(text));
                }
            }

            byte[] pwdBytes = Encoding.UTF8.GetBytes(password);

            byte[] keyBytes = new byte[16];

            int len = pwdBytes.Length;

            if (len > keyBytes.Length) len = keyBytes.Length;

            Array.Copy(pwdBytes, keyBytes, len);

            rijndaelCipher.Key = keyBytes;

            ICryptoTransform transform = rijndaelCipher.CreateDecryptor();

            byte[] plainText = transform.TransformFinalBlock(encryptedData, 0, encryptedData.Length);

            return Encoding.UTF8.GetString(plainText);
            //return Encoding.GetEncoding("GB2312").GetString(plainText);
        }

        #endregion 16 位 AES 加解密

        #region 32 位 AES 加密解密

        /// <summary>
        /// AES 加密。
        /// </summary>
        /// <param name="text"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static string AES32Encrypt(this string text, string password = "9D4#!uCb4%&83FO4")
        {
            var rijndaelCipher = new RijndaelManaged
            {
                Mode = CipherMode.ECB,
                Padding = PaddingMode.PKCS7,
                KeySize = 128,
                BlockSize = 128,
            };

            byte[] pwdBytes = Encoding.UTF8.GetBytes(password);

            byte[] keyBytes = pwdBytes;

            rijndaelCipher.Key = keyBytes;

            ICryptoTransform transform = rijndaelCipher.CreateEncryptor();

            byte[] plainText = Encoding.UTF8.GetBytes(text);

            byte[] cipherBytes = transform.TransformFinalBlock(plainText, 0, plainText.Length);
            string result = string.Empty;
            //逐字节变为16进制字符
            for (int i = 0; i < cipherBytes.Length; i++)
            {
                // Convert.ToString(cipherBytes[i], 16);
                result += cipherBytes[i].ToString("X2");
            }
            Console.WriteLine(result);
            return result;
        }

        /// <summary>
        /// AES 解密。
        /// </summary>
        /// <param name="text"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static string AES32Decrypt(this string text, string password = "9D4#!uCb4%&83FO4")
        {
            RijndaelManaged rijndaelCipher = new RijndaelManaged
            {
                Mode = CipherMode.ECB,
                Padding = PaddingMode.PKCS7,
                KeySize = 128,
                BlockSize = 128
            };

            //byte[] encryptedData = Encoding.UTF8.GetBytes(text);
            byte[] encryptedData = new byte[text.Length / 2];
            for (int i = 0; i < encryptedData.Length; i++)
            {
                try
                {
                    // 每两个字符是一个 byte。
                    encryptedData[i] = byte.Parse(text.Substring(i * 2, 2),
                    System.Globalization.NumberStyles.HexNumber);
                }
                catch
                {
                    // Rethrow an exception with custom message.
                    throw new ArgumentException("hex is not a valid hex number!", nameof(text));
                }
            }

            byte[] pwdBytes = Encoding.UTF8.GetBytes(password);

            var keyBytes = pwdBytes;

            rijndaelCipher.Key = keyBytes;

            ICryptoTransform transform = rijndaelCipher.CreateDecryptor();

            byte[] plainText = transform.TransformFinalBlock(encryptedData, 0, encryptedData.Length);

            return Encoding.UTF8.GetString(plainText);
        }

        #endregion 32 位 AES 加密解密

        #region SHA256 加密

        /// <summary>
        /// SHA256 加密。
        /// </summary>
        /// <param name="target">当前字符串。</param>
        /// <returns>加密后的字符串。</returns>
        public static string SHA256(this string target) => Convert.ToBase64String((new SHA256Managed()).ComputeHash(Encoding.UTF8.GetBytes(target)));

        #endregion SHA256 加密

        #region SHA512 加密

        /// <summary>
        /// SHA512 加密。
        /// </summary>
        /// <param name="target">当前字符串。</param>
        /// <returns>加密后的字符串。</returns>
        public static string SHA512(this string target)
        {
            byte[] bytValue = System.Text.Encoding.UTF8.GetBytes(target);
            try
            {
                SHA512 sha512 = new SHA512CryptoServiceProvider();
                byte[] retVal = sha512.ComputeHash(bytValue);
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < retVal.Length; i++)
                {
                    sb.Append(retVal[i].ToString("x2"));
                }
                return sb.ToString();
            }
            catch (Exception ex)
            {
                throw new Exception("GetSHA512HashFromString() fail,error:" + ex.Message);
            }
        }

        #endregion SHA512 加密
    }
}